////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef smartptr_h__
#define smartptr_h__

#include "core\types.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// \class	SmrtPtr
///
/// \brief	A simple SmartPointer as you should know it from other programs, or maybe
///			some Encyclopedia-stuff.
///			A SmartPointer takes care about the references pointing towards the pointer's
///			object. If the SmartPointer is released the object don't have to be deleted
///			yet. It will first be deleted when the refCounter is NULL.
///
///			There will also be an alternative Pointer, the so called WeakPointer.
///			If won't have any refcounting in mind which is also the main difference
///			between both.
///
/// \author	khaos
/// \date	12.12.2009
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
class SmrtPtr
{
	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	SmrtPtr()
		///
		/// \brief	Default constructor.
		///
		/// \author	khaos
		/// \date	12.12.2009
		////////////////////////////////////////////////////////////////////////////////////////////////////
		SmrtPtr();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	SmrtPtr(T * ptr)
		///
		/// \brief	Constructor.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param [in,out]	ptr	If non-null, the pointer.
		 ////////////////////////////////////////////////////////////////////////////////////////////////////
		SmrtPtr(T * ptr);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	SmrtPtr(const SmrtPtr<T> & rhs)
		///
		/// \brief	Copy constructor.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	rhs	The right hand side.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		SmrtPtr(const SmrtPtr<T> & rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	~SmrtPtr()
		///
		/// \brief	Finaliser.
		///
		/// \author	khaos
		/// \date	14.12.2009
		////////////////////////////////////////////////////////////////////////////////////////////////////
		~SmrtPtr();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void operator= (const SmrtPtr<T> & rhs)
		///
		/// \brief	Copy operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs	Another smart pointer.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void operator = (const SmrtPtr<T> & rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void operator= (T * rhs)
		///
		/// \brief	Copy operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs	Pointer for saving.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void operator = (T * rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator== (const SmrtPtr<T> & rhs) const
		///
		/// \brief	Equality operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs		Another smart pointer.
		///
		/// \return	True if both objects are the same, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator == (const SmrtPtr<T> & rhs) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator== (T * rhs) const
		///
		/// \brief	Equality operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs		Another pointer.
		///
		/// \return	True if both objects are the same, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator == (T * rhs) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator!= (const SmrtPtr<T> & rhs) const
		///
		/// \brief	Inequality operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs		Another smart pointer.
		///
		/// \return	True if both objects are inequal, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator != (const SmrtPtr<T> & rhs) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator!= (T * rhs) const
		///
		/// \brief	Inequality operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \param	[in]	rhs		Another pointer.
		///
		/// \return	True if both objects are inequal, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator != (T * rhs) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	T * operator-> () const
		///
		/// \brief	-> operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \return	The pointer.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		T * operator -> () const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	T & operator* () const
		///
		/// \brief	Dereference operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		///
		/// \return	The pointer.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		T & operator * () const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	operatorT * () const
		///
		/// \brief	Pointer cast operator.
		///
		/// \author	khaos
		/// \date	12.12.2009
		////////////////////////////////////////////////////////////////////////////////////////////////////
		operator T * () const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool isvalid() const
		///
		/// \brief	Returns if this smart pointer is valid.
		///
		/// \author	khaos
		/// \date	14.12.2009
		///
		/// \return	True if the smart pointer is valid, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool isvalid() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	T * get() const
		///
		/// \brief	Returns the pointer.
		///
		/// \author	khaos
		/// \date	14.12.2009
		///
		/// \return	The pointer.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		T * get() const;

	protected:

		T * m_ptr;

	private:

};





///
template<class T>
inline SmrtPtr<T>::SmrtPtr():
m_ptr(NULL)
{

}


///
template<class T>
inline SmrtPtr<T>::SmrtPtr(T *ptr):
m_ptr(ptr)
{
	if(this->m_ptr != NULL)
	{
		this->m_ptr->AddRef();
	}
}


///
template<class T>
inline SmrtPtr<T>::SmrtPtr(const SmrtPtr<T> &rhs):
m_ptr(rhs.m_ptr)
{
	if(this->m_ptr != NULL)
	{
		this->m_ptr->AddRef();
	}
}


///
template<class T>
inline SmrtPtr<T>::~SmrtPtr()
{
	if(this->m_ptr != NULL)
	{
		this->m_ptr->Release();

		this->m_ptr = 0;
	}
}





///
template<class T>
inline void SmrtPtr<T>::operator =(const SmrtPtr<T> &rhs)
{
	this->m_ptr = rhs.m_ptr;

	this->m_ptr->AddRef();
}


///
template<class T>
inline void SmrtPtr<T>::operator =(T *rhs)
{
	this->m_ptr = rhs;

	this->m_ptr->AddRef();
}


///
template<class T>
inline bool SmrtPtr<T>::operator ==(const SmrtPtr<T> &rhs) const
{
	return (this->m_ptr == rhs.m_ptr);
}


///
template<class T>
inline bool SmrtPtr<T>::operator ==(T *rhs) const
{
	return (this->m_ptr == rhs);
}


///
template<class T>
inline bool SmrtPtr<T>::operator !=(const SmrtPtr<T> &rhs) const
{
	return (this->m_ptr != rhs.m_ptr);
}


///
template<class T>
inline bool SmrtPtr<T>::operator !=(T *rhs) const
{
	return (this->m_ptr != rhs);
}


///
template<class T>
inline T * SmrtPtr<T>::operator ->() const
{
	return this->m_ptr;
}


///
template<class T>
inline SmrtPtr<T>::operator T *() const
{
	return this->m_ptr;
}


///
template<class T>
inline T & SmrtPtr<T>::operator *() const
{
	returnn &(this->m_ptr);
}





///
template<class T>
inline bool SmrtPtr<T>::isvalid() const
{
	return (this->m_ptr != NULL);
}


///
template<class T>
inline T * SmrtPtr<T>::get() const
{
	return this->m_ptr;
}

#endif // smartptr_h__